#include "stdafx.h"
#include "CppUnitTest.h"

#include <vex/iterable/stl_interop.h>
#include <vex.tests/mstest/tests.range/tests.range.h>

using namespace Microsoft::VisualStudio::CppUnitTestFramework;

namespace tests {	namespace range_stl_c_array {

    using namespace boost::assign;

    namespace vi = vex::iterable;

    TEST_CLASS(range_stl_c_array)
    {
        BEGIN_TEST_CLASS_ATTRIBUTE()
            TEST_CLASS_ATTRIBUTE(L"Module", L"tests.range.stl.c_array")
        END_TEST_CLASS_ATTRIBUTE();

        static const std::size_t m_container_size = 4u;
        typedef int container_t[m_container_size];
        typedef int* iterator_t;
        typedef int const* const_iterator_t;

        std::size_t container_size() const
        {
            return m_container_size;
        }
    public:
        TEST_METHOD(supports_move_and_swap)
        {
            VEX_TESTS_SCOPED_MEM_CHECK();

            container_t t_c1 = {
                1, 2, 3, 4
            };
            container_t t_c2 = {
                6, 7, 8, 9
            };

            auto t_r1 = vi::make_range(t_c1);
            auto t_r2 = vi::make_range(t_c2);

            random_access_range::has_expected_type_and_size<vi::stl_interop::range_from_iterator<iterator_t>>(
                t_r1, sizeof(vi::stl_interop::range_from_iterator<iterator_t>));
            random_access_range::has_expected_type_and_size<vi::stl_interop::range_from_iterator<iterator_t>>(
                t_r1, sizeof(vi::stl_interop::range_from_iterator<iterator_t>));

            auto t_c1_as_range = boost::make_iterator_range(t_c1);
            auto t_c2_as_range = boost::make_iterator_range(t_c2);
            random_access_range::supports_and_executes_swap_correctly(
                t_c1_as_range, t_c2_as_range, t_r1, t_r2);
        }

        TEST_METHOD(supports_non_const_to_const_conversion_but_not_vice_versa)
        {
            VEX_TESTS_SCOPED_MEM_CHECK();

            typedef decltype(vi::make_range(
                std::declval<iterator_t>(), std::declval<iterator_t>())) range_t;
            typedef decltype(vi::make_range(
                std::declval<const_iterator_t>(), std::declval<const_iterator_t>())) const_range_t;
            
            Assert::IsTrue(std::is_convertible<range_t, const_range_t>::value);
            Assert::IsFalse(std::is_convertible<const_range_t, range_t>::value);
        }

        TEST_METHOD(each_subsequent_move_front_or_move_back_decreases_size_by_one)
        {
            VEX_TESTS_SCOPED_MEM_CHECK();
            container_t c = {
                1, 2, 3, 4
            };

            random_access_range::size_always_has_expected_value(
                vi::make_range(c), this->container_size());

            random_access_range::each_subsequent_move_front_decreases_size_by_one(
                vi::make_range(c));

            random_access_range::each_subsequent_move_back_decreases_size_by_one(
                vi::make_range(c));
        }

        TEST_METHOD(vector_move_front_iteration_succeeds_expected_number_of_times)
        {
            VEX_TESTS_SCOPED_MEM_CHECK();
            container_t c = {
                1, 2, 3, 4
            };

            container_t c_empty;

            random_access_range::move_front_iteration_succeeds_expected_number_of_times(
                vi::make_range(c_empty), this->container_size());

            random_access_range::move_front_iteration_succeeds_expected_number_of_times(
                vi::make_range(c), this->container_size());

            random_access_range::move_front_iteration_succeeds_expected_number_of_times(
                vi::make_range(boost::begin(c), boost::end(c)), this->container_size());

            random_access_range::move_front_iteration_succeeds_expected_number_of_times(
                vi::make_range(boost::const_begin(c), boost::const_end(c)), this->container_size());
        }
    };
}}